A Verifying Custom Synchronisation Constructs Using Higher-Order Separation Logic

نویسندگان

  • MIKE DODDS
  • SURESH JAGANNATHAN
  • MATTHEW J. PARKINSON
  • KASPER SVENDSEN
چکیده

state well-formedness. In order to define formally that rs and d are well-formed and correspond correctly, we require several auxiliary notions: childd(x, i, y) , d(y).uhdr = x ∧ d(y).uoff = i ∧ 0 ≤ i ≤ d(x).loff leafd(〈x, i〉) , 〈x, i〉 ∈ d ∧ @y. d(y).uhdr = x ∧ d(y).uoff = i descendd(〈x, i〉, 〈y, j〉) , 〈x, i〉 = 〈y, j〉 ∨ descendd(〈x, i〉, 〈d(y).uhdr , d(y).uoff 〉) issetd(〈x, i〉) , d(x).flags(i) = 1 allsetd(x) , ∀i. 0 ≤ i ≤ d(x).loff =⇒ issetd(〈x, i〉) (Note we say that a location-offset pair 〈x, i〉 is in d if x ∈ dom(x)(d) ∧ i ≤ d.loff .) The child, descend, and leaf predicates record corresponding structural facts about relationships in the tree. Well-formedness on d (defined below) requires that paths through uhdr are finite, which suffices to ensure that descend is well-defined. isset and allset respectively assert that a single address and a whole array have their flags set. 〈x, i〉 iy a < d b , a <d b ∨ descendd(a, b) ∨ descendd(b, a) finalleafd(x, y) , descendd(x, y) ∧ leafd(y) ∧ (∀z. descendd(x, z) ∧ leafd(z)⇒ z < d y) The order predicate <d says that two addresses are ordered in the tree, meaning that they share a common ancestor array in which they are also ordered. This defines a transitive and irreflexive order. < d says that either two addresses are related by <d, or that one is the descendant of the other (i.e. they are on the same path and one summarises the other). finalleafd(x, y) indicates that y is the maximal leaf according to < d that is summarised by x. This is useful because applications of extend may mean clients wait on x when the actual leaf has been superceded by y. For each x there exists at most one y satisfying finalleaf, so we generally use it as a partial function, i.e. finalleafd(x) stands for the unique y such that finalleafd(x, y). We can now define wf(rs, d), which requires that rs and d are independently well-formed, and that they are correctly tied together. As abstract chains are unchanged from §6, we can reuse the prior definition of wf(rs) (§6.2). For heap-maps, well-formedness is defined as follows: wf(d) , ∃r : Addr.∃τ : dom(d)→ N. ∀x, i, y, z. (〈x, i〉 ∈ d =⇒ ∃j. descend(〈r, j〉, 〈x, i〉)) ∧ ((childd(x, i, y) ∧ childd(x, i, z)) =⇒ y = z) ∧ ((childd(x, i, y) ∧ issetd(x, i)) =⇒ allsetd(y)) ∧ (d(x).uhdr = y ∧ y 6= NULL =⇒ d(y) defined ∧ d(x).uoff ≤ d(y).loff ∧ τ(y) < τ(x)) Here the address r is the location of the tree root, while the function τ records the distance from the current node to the root – this enforces the absence of cycles. The first clause of the definition ensures all elements in the tree share a common root. The second ensures that children are uniquely identified by address and offset. The third ensures that setting a flag summarises all descendants. The final clause guarantees the existence of non-NULL parents to a node, and enforces the distance function τ . wf(rs, d) , wf(rs) ∧ wf(d) ∧ ∀r ∈ rs. r.loc = 〈l, o〉 =⇒ r.flg = d(l).flags[o] ∧ ∀r ∈ rs. leafd(r.loc) ∧ ∀r1, r2. (rs = · r1 · · r2 · ) =⇒ r2.loc <d r1.loc As well as requiring that rs and d are well-formed on their own, this requires (1) that flags in the chain are correctly set in the heap map; (2) locations in the chain are leaves in the heap map; and (3) order in the chain is reflected in the heap-map order <d. Transition map. We define a new transition map Ts to capture changes to the heap map (Figure 26). Many of the transitions are inherited from Tc, the transition relation for the chained implementation (§6.2). set and ext alter the underlying inverted-tree data-structure, and so are defined to allow this. set just updates the tree-map flag appropriately using our lens notation. ext has two cases, reflecting the conditional in the implementation. Either there is enough space in the array to fit another flag, or another array must be added to the heap map. In the latter case, note that the address of the existing channel a is shifted into the new array. Furthermore, signal can mark summary flags, i.e. flags that are not leaves in the tree; this is allowed by the transition mark. Finally, note finalleaf in the definition of get: this is needed because the real flag may shift its position due to extend, with wait left reading from a summary. Here x is the original flag which has been superceded, and finalleafd(x) is the current position of the flag. It is safe to pass an address to wait which may have been renuns(x, (rs, d), (rs ′, d′)) , d′ = d ∧ renunc(x, rs, rs′) sets(x, (rs, d), (rs ′, d′)) , x = 〈h, o〉 ∧ d′ = d JhJflags[o] (1) ∧ setc(〈h, o〉, rs, rs′) exts(x, (rs, d), (rs ′, d′)) , rs = (rs1 · a · rs2) ∧ rs′ = (rs1 · b · c · rs2) ∧ a.flg = 0 ∧ ∃y. b = a[loc 7→ y] ∧ c.flg = 0 ∧ c.W = ∅ ∧ x = 〈h, o〉 = a.loc ∧ áÇ b.off = 〈h′, 0〉 ∧ c.off = 〈h′, 1〉 ∧ d′ = d ] h′ 7→ {uhdr = h; uoff = o; loff = 1; flags = λ . 0} å ∨ Ç o = d(h).loff ∧ b.loc = a.loc ∧ c.loc = 〈h, o+ 1〉 ∧ d′ = (d JhJloff (o+ 1)) JhJflags[o+1] (0)) å ë splits(x, r, (rs, d), (rs ′, d′)) , d = d′ ∧ splitc(finalleafd(x), r, rs, rs′) sats((rs, d), (rs ′, d′)) , d = d′ ∧ satc(rs, rs′) gets(x, r, (rs, d), (rs ′, d′)) , d = d′ ∧ getc(finalleafd(x), r, rs, rs′) Ts(send(x)) , {(a, b) | wf(b) ∧ (renuns(x, a, b) ∨ sets(x, a, b) ∨ exts(x, a, b))} Ts(change(x, r)) , {(a, b) | wf(b) ∧ (splits(x, r, a, b) ∨ sats(a, b) ∨ gets(x, r, a, b))} Ts(mark) , ® ((rs, d), (rs, d′)) wf(rs, d′) ∧ d′ = d JhJflags[o] (1) ∧ ¬leafd(〈h, o〉)) ́ Fig. 26. Definition of the transition relation Ts for the summarising implementation. converted into a summary because extension ensures the original flag must be one of those summarised by x. Interpretation function. For a given map d, chainds maps down to the corresponding datastructure definition. Heap maps are intentionally close to the underlying heap: each element in the domain maps to a distinct chan addr object in memory. chainds(d) , x∈dom(d). x.up 7 7→ {hdr = d(x).uhdr ; off = d(x).uoff } ∗ x.loff 7→ (d(x).loff ) ∗ i∈{0..MAX}. x.flags[i] 7→ (d(x).flags(i)) Once a chan addr object has been allocated, its up-address cannot be modified. To represent this in the definition, we write x 7 7→ v to indicate that x is immutable – shorthand for ∃f. x f 7−→ v. This is useful as immutable locations can be freely shared between threads: x 7 7→ v =⇒ x 7 7→ v ∗ x 7 7→ v. The interpretation function Is converts an abstract state Chain(rs, d) into a datastructure: Is(r)(Chain(rs, d)) , chainds(d) ∗ chainres(rs) ∗ unused(r, rs, d) As chainds defines the concrete heap structure, it only requires a heap-map d. Conversely, chainres defines the pattern of splits, promises, and renunciations, and so only requires an abstract chain rs. Indeed, chainres is defined identically to §6. The predicate unused, representing the ‘library’ of unused permissions, requires both d and rs. This is because the position of a flag may move as a result of extension. As a result, wait may be passed a summary flag x – before extension, the passed node would have been a leaf. The flag x will be represented in d, but not represented in the chain rs, and thus unused requires both in order to keep track of permissions. To define unused, the set C(rs, d) represents possible targets of wait; a permission is missing from the set of unused change permissions, uC(rs, d), only if it targets one of these

برای دانلود متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

منابع مشابه

Verifying Higher-Order Imperative Programs with Higher-Order Separation Logic

In this thesis I show is that it is possible to give modular correctness proofs of interesting higher-order imperative programs using higher-order separation logic. To do this, I develop a model higher-order imperative programming language, and develop a program logic for it. I demonstrate the power of my program logic by verifying a series of examples, culminating in the correctness proof of a...

متن کامل

Verifying Parallel Loops with Separation Logic

This paper proposes a technique to specify and verify whether a loop can be parallelised. Our approach can be used as an additional step in a parallelising compiler to verify user annotations about loop dependences. Essentially, our technique requires each loop iteration to be specified with the locations it will read and write. From the loop iteration specifications, the loop (in)dependences c...

متن کامل

Characteristic Formulae for the Veri cation of Imperative Programs

We have developed characteristic formulae as a technique for verifying imperative programs using interactive theorem provers. The characteristic formula of a program is a higher-order logic formula that gives a sound and complete description of the semantics of this program without referring to its source code. The formula can be constructed automatically from the source code it describes, in a...

متن کامل

Towards Algebraic Separation Logic

We present an algebraic approach to separation logic. In particular, we give algebraic characterisations for all constructs of separation logic like assertions and commands. The algebraic view does not only yield new insights on separation logic but also shortens proofs and enables the use of automated theorem provers for verifying properties at a more abstract level.

متن کامل

Verifying Object-Oriented Programs with Higher-Order Separation Logic in Coq

We present a shallow Coq embedding of a higher-order separation logic with nested triples for an object-oriented programming language. Moreover, we develop novel specification and proof patterns for reasoning in higher-order separation logic with nested triples about programs that use interfaces and interface inheritance. In particular, we show how to use the higher-order features of the Coq fo...

متن کامل

A Resource-Sensitive Synchronization Inference by Abduction

We present an analysis which takes as its input a sequential program, augmented with annotations indicating potential parallelization opportunities, and a sequential proof, written in separation logic, and produces a correctly-synchronized parallelized program and proof of that program. Unlike previous work, ours is not an independence analysis; we insert synchronization constructs to preserve ...

متن کامل

ذخیره در منابع من


  با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید

برای دانلود متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

عنوان ژورنال:

دوره   شماره 

صفحات  -

تاریخ انتشار 2015